#include <stdio.h>
#include <stdlib.h>

#include "body.h"
#include "common.h"

//f ree bodyList ptr
void freeBodyList(bodyList* bl)
{
	if (bl->pinned)
	{
		cudaFreeHost(bl->pos);
		cudaFreeHost(bl->vel);
	}
	else
	{
		free(bl->pos);
		free(bl->vel);
	}
	free(bl);
}

void convertPinnedBodyList(bodyList* bl)
{
	float4* old_pos = bl->pos;
	float4* old_vel = bl->vel;

	bl->pos = (float4*) safe_cudaMallocHost(bl->size*sizeof(float4));
	bl->vel = (float4*) safe_cudaMallocHost(bl->size*sizeof(float4));
	bl->pinned = true;
	
	cudaMemcpy(bl->pos, old_pos, bl->size*sizeof(float4), cudaMemcpyHostToHost);
	cudaMemcpy(bl->vel, old_vel, bl->size*sizeof(float4), cudaMemcpyHostToHost);

	free(old_pos);
	free(old_vel);
}

void allocBodyList(bodyList* bl, int num_bodies)
{
	bl->pos = (float4*) safe_malloc(num_bodies*sizeof(float4));
	bl->vel = (float4*) safe_malloc(num_bodies*sizeof(float4));
	bl->size = 0;
	bl->capacity = num_bodies;
	bl->pinned = false;
}

void reallocBodyList(bodyList* bl, int num_bodies)
{
	bl->pos = (float4*) safe_realloc(bl->pos, num_bodies*sizeof(float4));
	bl->vel = (float4*) safe_realloc(bl->vel, num_bodies*sizeof(float4));
	bl->capacity = num_bodies;
}

//read positions and velocities
bodyList* readBodyList()
{
	return readBodyList(stdin);
}

bodyList* readBodyList(const char* filename)
{
	bodyList* bl;

	FILE *f = fopen(filename, "r");
	if (f != NULL)
	{
		bl = readBodyList(f);
		fclose(f);
	}
	else
	{
		bl = NULL;
	}

	return bl;
}

bodyList* readBodyList(FILE* stream)
{
	// allocate body list
	bodyList* bl = (bodyList*) safe_malloc(sizeof(bodyList));
	allocBodyList(bl, 2);

	while (1)
	{
		float4* pos = &bl->pos[bl->size];
		float4* vel = &bl->vel[bl->size];
		int status = fscanf(stream, "%f %f %f %f %f %f %f\n", &pos->x, &pos->y, &pos->z,
			&vel->x, &vel->y, &vel->z, &pos->w);

		vel->w = 0.0f;

		if (status == EOF)
			break;

		if (status != 7)
			inputError();

		++bl->size;

		if (bl->size == bl->capacity)
			reallocBodyList(bl, 2*bl->capacity);
	}

	return bl;
}

void writeBodyList(bodyList* bl)
{
	writeBodyList(bl, stdout);
}

void writeBodyList(bodyList* bl, const char* filename)
{
	FILE *f = fopen(filename, "w");
	if (f != NULL)
	{
		writeBodyList(bl, f);
		fclose(f);
	}
}

void writeBodyList(bodyList* bl, FILE* stream)
{
	int i;
	for (i = 0; i != bl->size; ++i)
	{   
		float4* pos = &bl->pos[i];
		float4* vel = &bl->vel[i];
		fprintf(stream,
			//"%9.2f %9.2f %9.2f %9.2f %9.2f %9.2f %9.2f\n",
			//"%f %f %f %f %f %f %f\n",
			//"%e %e %e %e %e %e %e\n",
			"%9.2e %9.2e %9.2e %9.2e %9.2e %9.2e %9.2e\n",
			pos->x, pos->y, pos->z, vel->x, vel->y, vel->z, pos->w);
	}
}
